// 默认内置武将（指向项目中实际存在的图片文件）
// 注意：ID必须与数据库中的ID保持一致
const DEFAULT_HEROES = [
  { id: 1, name: '赵云', image_url: 'img/赵云.png', faction: '蜀' },
  { id: 2, name: '关羽', image_url: 'img/关羽.png', faction: '蜀' },
  { id: 7, name: '貂蝉', image_url: 'img/貂蝉.jpg', faction: '群' },
  { id: 8, name: '张让', image_url: 'img/张让.jpg', faction: '群' },
  { id: 9, name: '杨彪', image_url: 'img/杨彪.PNG', faction: '群' },
  { id: 10, name: '戏志才', image_url: 'img/戏志才.jpeg', faction: '魏' },
  { id: 11, name: '荀彧', image_url: 'img/荀彧.jpeg', faction: '魏' },
  { id: 12, name: '钟会', image_url: 'img/钟会.jpeg', faction: '魏' }
];

// 图片 URL 规范化：如果是相对路径（不以 http:// https:// 或 / 开头），在前面加上 /static/
// 注意：不对中文文件名进行编码，因为静态服务器会自动处理
function normalizeImageUrl(url){
  if(!url) return '/static/img/placeholder.svg';
  if(/^https?:\/\//i.test(url)) return url;
  if(/^\//.test(url)) return url; // already absolute from server root
  // relative path like img/xxx.jpg -> /static/img/xxx.jpg
  return '/static/' + url.replace(/^\/+/, '');
}
// 异步检测一个 URL 是否存在图片（用于尝试按名称在 /static/img 下查找文件）
function testImageLoad(url, timeout = 1200){
  return new Promise(resolve => {
    const img = new Image();
    let settled = false;
    const onLoad = () => { if(!settled){ settled = true; cleanup(); resolve(true); } };
    const onErr = () => { if(!settled){ settled = true; cleanup(); resolve(false); } };
    const cleanup = () => { img.onload = img.onerror = null; clearTimeout(timer); };
    img.onload = onLoad; img.onerror = onErr;
    img.src = url;
    const timer = setTimeout(()=>{ if(!settled){ settled = true; cleanup(); resolve(false); } }, timeout);
  });
}

// 按武将名在 /static/img 下尝试多个后缀查找图片，返回相对路径（img/xxx.ext）或空字符串
async function findLocalImageForName(name){
  if(!name) return '';
  const exts = ['png','jpg','jpeg','PNG','JPG','JPEG','svg'];
  for(const ext of exts){
    // 尝试加载图片（不编码，直接使用中文文件名）
    const url = '/static/img/' + name + '.' + ext;
    // 测试是否能加载
    try{
      const ok = await testImageLoad(url);
      if(ok){
        // 返回相对路径
        return 'img/' + name + '.' + ext;
      }
    }catch(e){ /* ignore */ }
  }
  return '';
}

const HEROES_KEY = 'sanguosha_heroes_v1';
function loadHeroes(){
  try{
    const raw = localStorage.getItem(HEROES_KEY);
    const user = raw? JSON.parse(raw) : [];
    // merge default + user
    // ensure image_url normalized for all heroes returned
    const merged = DEFAULT_HEROES.concat(user || []);
    return merged.map(h=> ({ ...h, image_url: normalizeImageUrl(h.image_url) }));
  }catch(e){ console.error('loadHeroes error', e); return DEFAULT_HEROES.slice(); }
}
function saveHero(h){
  try{
    const raw = localStorage.getItem(HEROES_KEY);
    const arr = raw? JSON.parse(raw): [];
    // 直接保存，不再处理 image_url
    const heroToSave = { ...h };
    const exists = arr.some(x=>Number(x.id)===Number(heroToSave.id));
    if(!exists) arr.push(heroToSave);
    localStorage.setItem(HEROES_KEY, JSON.stringify(arr));
  }catch(e){ console.error('saveHero error', e); }
}

async function ensureHeroInSample(h){
  if(!h) return;
  const found = sampleHeroes.find(x=>Number(x.id)===Number(h.id));
  if(found) return;

  // 处理图片 URL
  let imageUrl = h.image_url || h.image || '';

  // 如果没有 image_url，尝试按名字查找本地静态图片
  if(!imageUrl){
    const candidate = await findLocalImageForName(h.name);
    if(candidate) imageUrl = candidate; // e.g. 'img/张让.jpg'
  }

  // 创建武将对象（保留相对路径，不在这里规范化）
  const heroObj = {
    id: Number(h.id),
    name: h.name || '',
    image_url: imageUrl,  // 保持原始格式
    faction: h.faction || ''
  };

  saveHero(heroObj);
  sampleHeroes = loadHeroes();
}

let sampleHeroes = loadHeroes();

const sampleUsers = [
  { id: 'u1', nickname: '玩家甲', avatar_url: normalizeImageUrl('img/avatar1.svg') },
  { id: 'u2', nickname: '玩家乙', avatar_url: normalizeImageUrl('img/avatar2.svg') },
  { id: 'u3', nickname: '玩家丙', avatar_url: normalizeImageUrl('img/avatar3.svg') }
];

// rooms persisted in localStorage so new rooms survive refresh
const ROOMS_KEY = 'sanguosha_rooms_v1';
function loadRooms(){
  try{
    const raw = localStorage.getItem(ROOMS_KEY);
    if(raw){
      const parsed = JSON.parse(raw);
      // normalize hero ids
      parsed.forEach(r=>{ if(Array.isArray(r.heroes)) r.heroes = r.heroes.map(h=> h==null? null : Number(h)); });
      return parsed;
    }
  }catch(e){ console.error('loadRooms error', e); }
  // default room
  return [ { id: 'ROOM111', creator_id: 'u1', mode: '8人', status: '等待中', max_players: 8, current_players: 3, heroes: [] } ];
}
function saveRooms(){
  try{
    // normalize hero ids
    const toSave = JSON.parse(JSON.stringify(rooms));
    toSave.forEach(r=>{ if(Array.isArray(r.heroes)) r.heroes = r.heroes.map(h=> h==null? null : Number(h)); });
    localStorage.setItem(ROOMS_KEY, JSON.stringify(toSave));
  }catch(e){ console.error('saveRooms error', e); }
}

let rooms = loadRooms();

// userChoices 持久化到 localStorage
const CHOICES_KEY = 'sanguosha_choices_v1';
function loadChoices(){
  try{
    const raw = localStorage.getItem(CHOICES_KEY);
    return raw ? JSON.parse(raw) : [];
  }catch(e){ console.error('loadChoices error', e); return []; }
}
function saveChoices(){
  try{
    localStorage.setItem(CHOICES_KEY, JSON.stringify(userChoices));
  }catch(e){ console.error('saveChoices error', e); }
}

let userChoices = loadChoices();

// 简单 DOM helpers
const $ = sel => document.querySelector(sel);
const $$ = sel => Array.from(document.querySelectorAll(sel));

// 全局加载和错误提示
function showLoading(msg = '加载中...'){
  let loader = document.getElementById('global-loader');
  if(!loader){
    loader = document.createElement('div');
    loader.id = 'global-loader';
    loader.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.8);color:#fff;padding:16px 24px;border-radius:8px;z-index:9999;font-size:14px;';
    document.body.appendChild(loader);
  }
  loader.textContent = msg;
  loader.style.display = 'block';
}

function hideLoading(){
  const loader = document.getElementById('global-loader');
  if(loader) loader.style.display = 'none';
}

function showError(msg){
  alert('错误: ' + msg);
  hideLoading();
}

function init(){
  renderRecentRooms();
  bindActions();
  showHome();
}

function bindActions(){
  $('#createRoomBtn').addEventListener('click', showCreateRoom);
  $('#joinRoomBtn').addEventListener('click', showJoinRoom);
  $('#rulesBtn').addEventListener('click', showRules);
  $('#historyBtn').addEventListener('click', showHistory);
  // 全局返回首页导航按钮
  const backNav = document.getElementById('backHomeNav');
  if(backNav) backNav.addEventListener('click', ()=>{ showHome(); });
  // 顶部 mini-back 按钮（小程序风格）
  const miniBack = document.getElementById('mini-back');
  if(miniBack) miniBack.addEventListener('click', ()=>{ showHome(); });
  // 底部 tabbar 行为（首页 / 房间 / 我的）
  const tabs = document.querySelectorAll('.mini-tabbar .tab-item');
  if(tabs && tabs.length){
    tabs.forEach((tab, idx)=>{
      tab.addEventListener('click', ()=>{
        // 切换 active
        tabs.forEach(t=>t.classList.remove('active'));
        tab.classList.add('active');
        // 触发对应视图
        if(idx===0) showHome();
        else if(idx===1) showCreateRoom();
        else if(idx===2) showHistory();
      });
    });
  }

  // 绑定武将搜索控件
  const heroBtn = document.getElementById('heroSearchBtn');
  const heroInput = document.getElementById('heroSearchInput');
  if(heroBtn && heroInput){
    heroBtn.addEventListener('click', ()=>{
      const term = heroInput.value.trim();
      searchHeroes(term);
    });
    heroInput.addEventListener('keypress', (e)=>{ if(e.key==='Enter'){ searchHeroes(heroInput.value.trim()); } });
  }

  // 添加武将按钮与模态操作
  const addHeroBtn = document.getElementById('addHeroBtn');
  const addHeroModal = document.getElementById('addHeroModal');
  const addHeroForm = document.getElementById('addHeroForm');
  const cancelAdd = document.getElementById('cancelAddHero');
  if(addHeroBtn && addHeroModal){
    addHeroBtn.addEventListener('click', ()=>{ addHeroModal.classList.remove('hidden'); });
    // 保守绑定：确保取消按钮总能生效
    if(cancelAdd){
      cancelAdd.addEventListener('click', ()=>{ addHeroModal.classList.add('hidden'); if(addHeroForm) addHeroForm.reset(); });
    }
    // 如果 addHeroForm 在绑定时不存在，使用事件代理处理提交
    if(addHeroForm){
      addHeroForm.addEventListener('submit', async (e)=>{
      e.preventDefault();
      const fd = new FormData(addHeroForm);
      showLoading('上传中...');
      try{
        const resp = await fetch('/api/heroes', { method: 'POST', body: fd });
        const json = await resp.json();
        hideLoading();
        if(json && json.ok){
          alert('添加成功');
          // 构建可直接用于 <img> 的 image_url
          let imageUrl = 'img/placeholder.png';
          if(json.image_url){
            if(/^https?:\/\//i.test(json.image_url) || /^\//.test(json.image_url)){
              imageUrl = json.image_url;
            } else {
              imageUrl = '/static/' + json.image_url.replace(/^\/+/, '');
            }
          }
          const newHero = {
            id: json.id ? Number(json.id) : (sampleHeroes.length + 1),
            name: fd.get('name'),
            faction: fd.get('faction') || '',
            image_url: imageUrl
          };
          // persist new hero to local storage and refresh in-memory list
          saveHero(newHero);
          sampleHeroes = loadHeroes();
          addHeroModal.classList.add('hidden');
          addHeroForm.reset();
        } else {
          showError(json.error || '未知错误');
        }
      }catch(err){
        showError('请求失败: ' + err.message);
      }
      });
    } else {
      // 事件代理：页面层捕获表单提交（兜底）
      document.addEventListener('submit', async (e)=>{
        if(e.target && e.target.id==='addHeroForm'){
          e.preventDefault();
          const form = e.target;
          const fd = new FormData(form);
          try{
            const resp = await fetch('/api/heroes', { method: 'POST', body: fd });
            const json = await resp.json();
            if(json && json.ok){ alert('添加成功'); form.reset(); document.getElementById('addHeroModal').classList.add('hidden'); }
            else alert('添加失败: '+(json.error||'未知'));
          }catch(err){ alert('请求失败:'+err.message); }
        }
      });
    }
  }
  // fallback: 如果页面中某些元素未被正常绑定（极少数情况），添加 document 事件作为兜底
  document.addEventListener('click', (e)=>{
    if(e.target && e.target.id==='addHeroBtn'){
      const modal = document.getElementById('addHeroModal'); if(modal) modal.classList.remove('hidden');
    }
  });
}

// 统一的武将搜索函数（减少重复代码）
async function fetchHeroByName(term){
  if(!term) return null;
  try{
    const resp = await fetch(`/api/heroes?name=${encodeURIComponent(term)}`);
    const json = await resp.json();
    if(json && json.ok && Array.isArray(json.data) && json.data.length > 0){
      const hero = json.data[0]; // 返回第一个匹配的武将
      // 确保武将被添加到本地缓存中
      await ensureHeroInSample(hero);
      // 返回从 sampleHeroes 中获取的武将对象（已经规范化过）
      return sampleHeroes.find(h => Number(h.id) === Number(hero.id)) || hero;
    }
  }catch(err){
    console.error('fetchHeroByName error:', err);
  }
  // 回退到本地搜索（优先精确匹配）
  const exactMatch = sampleHeroes.find(h => h.name === term);
  if(exactMatch) return exactMatch;
  // 如果没有精确匹配，尝试模糊匹配
  return sampleHeroes.find(h => h.name.includes(term)) || null;
}

function searchHeroes(term){
  const area = document.getElementById('searchResults');
  if(!area) return;
  area.classList.remove('hidden');
  if(!term){ area.innerHTML = '<div class="small">请输入搜索词</div>'; return; }
  // 优先请求后端 API
  fetch(`/api/heroes?name=${encodeURIComponent(term)}`).then(r=>r.json()).then(json=>{
    if(json && json.ok && Array.isArray(json.data) && json.data.length>0){
      const html = json.data.map(h=>{
        const img = normalizeImageUrl(h.image_url);
        // add onerror to fallback to placeholder when image fails to load
        return `<div class="hero-card" data-hero="${h.id}"><img src="${img}" alt="${h.name}" onerror="this.onerror=null;this.src='/static/img/placeholder.svg'"/><div class="small">${h.name}</div></div>`;
      }).join('');
      area.innerHTML = `<h4>搜索结果</h4><div class="hero-grid">${html}</div>`;
    }else{
      // 后端返回空结果或格式不对，回退本地（优先精确匹配）
      const exactMatch = sampleHeroes.find(h => h.name === term);
      const matches = exactMatch ? [exactMatch] : sampleHeroes.filter(h => h.name.includes(term));
      if(matches.length===0){ area.innerHTML = `<div class="small">未找到"${term}"的武将</div>`; return; }
  const html = matches.map(h=>`<div class="hero-card" data-hero="${h.id}"><img src="${normalizeImageUrl(h.image_url)}" alt="${h.name}" onerror="this.onerror=null;this.src='/static/img/placeholder.svg'"/><div class="small">${h.name}</div></div>`).join('');
      area.innerHTML = `<h4>搜索结果（本地）</h4><div class="hero-grid">${html}</div>`;
    }
  }).catch(err=>{
    // 请求失败则回退本地数据（优先精确匹配）
    const exactMatch = sampleHeroes.find(h => h.name === term);
    const matches = exactMatch ? [exactMatch] : sampleHeroes.filter(h => h.name.includes(term));
    if(matches.length===0){ area.innerHTML = `<div class="small">未找到"${term}"的武将（本地）</div>`; return; }
  const html = matches.map(h=>`<div class="hero-card" data-hero="${h.id}"><img src="${normalizeImageUrl(h.image_url)}" alt="${h.name}" onerror="this.onerror=null;this.src='/static/img/placeholder.svg'"/><div class="small">${h.name}</div></div>`).join('');
  area.innerHTML = `<h4>搜索结果（本地）</h4><div class="hero-grid">${html}</div>`;
  });
}

function renderRecentRooms(){
  const ul = $('#recentRoomsList');
  ul.innerHTML = '';
  // 只显示最近的 5 个房间
  const recentRooms = rooms.slice(0, 5);
  recentRooms.forEach(r => {
    const li = document.createElement('li');
    li.innerHTML = `<span><span class="room-id">${r.id}</span> <span class="room-meta">(${r.mode} · ${r.current_players}/${r.max_players})</span></span>
    <span class="room-actions">
      <button data-id="${r.id}" class="openRoomBtn">进入</button>
      <button data-id="${r.id}" class="deleteRoomBtn">删除</button>
    </span>`;
    ul.appendChild(li);
  });
  $$('.openRoomBtn').forEach(b=>b.addEventListener('click', e=>openRoom(e.target.dataset.id)));
  $$('.deleteRoomBtn').forEach(b=>b.addEventListener('click', e=>deleteRoom(e.target.dataset.id)));
}

function deleteRoom(roomId){
  if(!confirm(`确定要删除房间 ${roomId} 吗？`)) return;
  const index = rooms.findIndex(r=>r.id===roomId);
  if(index >= 0){
    rooms.splice(index, 1);
    saveRooms();
    renderRecentRooms();
    // 同时删除该房间的所有用户选择
    userChoices = userChoices.filter(c=>c.room_id !== roomId);
    saveChoices();
  }
}

function showHome(){
  $('#mainView').innerHTML = `<h3>欢迎</h3><p class="small">请选择“创建房间”或“加入房间”开始。</p>`;
  // 恢复房间进入按钮（如果之前被禁用）
  document.querySelectorAll('.openRoomBtn').forEach(b=>b.disabled=false);
}

function showCreateRoom(){
  document.querySelectorAll('.openRoomBtn').forEach(b=>b.disabled=true);
  const html = `
    <h3>创建房间</h3>
    <div class="controls">
      <label>模式： <select id="createMode"><option value="8人">8人</option><option value="5人">5人</option></select></label>
      <label> 最大人数： <input id="createMax" type="number" value="8" min="4" max="10"/></label>
      <button id="doCreate">创建</button>
    </div>
    <div id="createPreview" class="small">创建后会生成对应数量的武将框，可选择或搜索武将。</div>
  `;
  $('#mainView').innerHTML = html;
  $('#doCreate').addEventListener('click', async ()=>{
    const mode = $('#createMode').value;
    const max = parseInt($('#createMax').value,10)||8;
    const id = 'R'+Math.random().toString(36).slice(2,8).toUpperCase();

    // 新建房间
    const room = { id, creator_id: sampleUsers[0].id, mode, status: '等待中', max_players: max, current_players: 1, heroes: [] };

    // 先保存到数据库
    showLoading('创建房间中...');
    try{
      const resp = await fetch('/api/rooms', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(room)
      });
      const json = await resp.json();
      if(!json || !json.ok){
        hideLoading();
        showError('创建房间失败: ' + (json.error || '未知错误'));
        return;
      }
      hideLoading();
    }catch(err){
      hideLoading();
      showError('创建房间失败: ' + err.message);
      return;
    }

    // 数据库创建成功后，再保存到本地
    rooms.unshift(room);
    saveRooms();
    renderRecentRooms();
    openRoom(id);
  });
}

function showJoinRoom(){
  const html = `
    <h3>加入房间</h3>
    <div class="controls">
      <input id="joinRoomId" placeholder="输入房间ID，例如 ROOM111" />
      <button id="doJoin">加入</button>
    </div>
    <div id="joinMsg" class="small"></div>
  `;
  $('#mainView').innerHTML = html;
  $('#doJoin').addEventListener('click', async ()=>{
    const id = $('#joinRoomId').value.trim();

    // 先从服务器检查房间是否存在
    showLoading('加入房间中...');
    try{
      const resp = await fetch(`/api/rooms/${id}`);
      const json = await resp.json();
      if(!json || !json.ok){
        hideLoading();
        $('#joinMsg').textContent='未找到房间';
        return;
      }

      const room = json.data;
      if(room.current_players >= room.max_players){
        hideLoading();
        $('#joinMsg').textContent='房间已满';
        return;
      }

      // 调用加入接口
      const joinResp = await fetch(`/api/rooms/${id}/join`, { method: 'PUT' });
      const joinJson = await joinResp.json();
      if(!joinJson || !joinJson.ok){
        hideLoading();
        $('#joinMsg').textContent='加入失败: ' + (joinJson.error || '未知错误');
        return;
      }

      hideLoading();
      // 更新本地数据
      const localRoom = rooms.find(r=>r.id===id);
      if(localRoom){
        localRoom.current_players = room.current_players + 1;
        localRoom.heroes = room.heroes || [];
      } else {
        room.current_players += 1;
        rooms.unshift(room);
      }
      saveRooms();
      renderRecentRooms();
      openRoom(id);
    }catch(err){
      hideLoading();
      $('#joinMsg').textContent='加入失败: ' + err.message;
    }
  });
}

function showRules(){
  $('#mainView').innerHTML = `<h3>规则说明</h3><div class="small">${document.querySelector('pre')? document.querySelector('pre').textContent: '1. 创建或加入房间\n2. 选择每个武将的身份（主公/忠臣/反贼/内奸）\n3. 提交后查看身份选择分布'}</div>`;
}

function showHistory(){
  // 显示最多 15 个历史房间
  const historyRooms = rooms.slice(0, 15);

  if(historyRooms.length === 0){
    $('#mainView').innerHTML = `<h3>历史记录</h3><div class="small">暂无历史记录</div>`;
    return;
  }

  const roomsList = historyRooms.map(r => {
    return `
      <div class="history-room-item">
        <div class="history-room-info">
          <div class="room-id">${r.id}</div>
          <div class="room-meta">${r.mode} · ${r.current_players}/${r.max_players} · ${r.status}</div>
          <div class="small" style="color:#999;">创建者: ${r.creator_id}</div>
        </div>
        <div class="room-actions">
          <button class="openRoomBtn" data-id="${r.id}">进入</button>
          <button class="deleteRoomBtn" data-id="${r.id}">删除</button>
        </div>
      </div>
    `;
  }).join('');

  $('#mainView').innerHTML = `
    <h3>历史记录 <span class="small">(最多显示15条)</span></h3>
    <div class="history-rooms-list">${roomsList}</div>
  `;

  // 绑定按钮事件
  $$('.openRoomBtn').forEach(b=>b.addEventListener('click', e=>{
    const roomId = e.target.dataset.id;
    openRoom(roomId);
  }));
  $$('.deleteRoomBtn').forEach(b=>b.addEventListener('click', e=>{
    const roomId = e.target.dataset.id;
    deleteRoom(roomId);
  }));
}

async function openRoom(roomId){
  let room = rooms.find(r=>r.id===roomId);
  if(!room) return;

  // 从服务器加载房间信息（包含武将列表）
  try{
    showLoading('加载房间数据...');
    const resp = await fetch(`/api/rooms/${roomId}`);
    const json = await resp.json();
    if(json && json.ok && json.data){
      // 更新本地房间数据
      const serverRoom = json.data;
      const localRoomIndex = rooms.findIndex(r=>r.id===roomId);
      if(localRoomIndex >= 0){
        rooms[localRoomIndex].heroes = serverRoom.heroes || [];
        room = rooms[localRoomIndex];
        saveRooms();
      }
    }
    hideLoading();
  }catch(err){
    console.error('加载房间信息失败:', err);
    hideLoading();
  }

  // 预加载房间中的所有武将信息（从数据库获取并缓存到本地）
  if(room.heroes && room.heroes.length > 0){
    const validHeroIds = room.heroes.filter(hid => hid != null && Number.isFinite(Number(hid)));
    if(validHeroIds.length > 0){
      try{
        // 批量获取武将信息
        for(const hid of validHeroIds){
          const existInLocal = sampleHeroes.find(h => Number(h.id) === Number(hid));
          if(!existInLocal){
            // 如果本地没有，从数据库获取
            const resp = await fetch(`/api/heroes?id=${hid}`);
            const json = await resp.json();
            if(json && json.ok && json.data && json.data.length > 0){
              await ensureHeroInSample(json.data[0]);
            }
          }
        }
      }catch(err){
        console.error('预加载武将失败:', err);
      }
    }
  }

  // 确保展示的武将数量与房间模式一致（例如 8人房显示 8 个框）
  const expectedCount = room.mode && room.mode.includes('5')? 5 : 8;
  const heroIds = room.heroes.slice(0);
  // 如果 heroes 列表不足,填充占位 null（表示空位）
  while(heroIds.length < expectedCount) heroIds.push(null);
  const heroCards = heroIds.map((hid, idx)=>{
    const hero = (hid ? sampleHeroes.find(h=>Number(h.id)===Number(hid)) : null);
    // sampleHeroes 中的 image_url 已经在 loadHeroes 中规范化过了，直接使用
    const displayImage = hero && hero.image_url ? hero.image_url : '/static/img/placeholder.svg';
    const displayName = hero && hero.name ? hero.name : '';
    // data-hero 只有在已选择武将时才写入 id
    const dataAttr = hero && hero.id ? `data-hero="${hero.id}"` : '';
    return `
      <div class="hero-card" ${dataAttr}>
        <img src="${displayImage}" alt="${displayName}" onerror="this.onerror=null;this.src='/static/img/placeholder.svg'" />
        <div class="name-input"><input class="card-name" placeholder="请输入武将姓名（可留空）" value="${displayName}" /></div>
        <div class="identity-select">身份：<select class="identitySel"><option value="未知">未知</option><option value="主公">主公</option><option value="忠臣">忠臣</option><option value="反贼">反贼</option><option value="内奸">内奸</option></select></div>
        <div class="hero-search-input"><input class="card-search" placeholder="搜索并替换武将名（回车）" /></div>
      </div>
    `;
  }).join('');

  const html = `
    <h3>房间：${room.id} <span class="small">(${room.mode} · ${room.current_players}/${room.max_players})</span></h3>
    <div class="controls">
      <button id="copyLink">复制房间链接</button>
      <button id="submitChoices">提交选择</button>
    </div>
    <div class="hero-grid">${heroCards}</div>
    <h4>提交结果</h4>
    <div id="resultsArea"><div class="small">尚未达到显示条件（至少2人提交）</div></div>
    <h4>已提交用户</h4>
    <div id="submittedUsers" class="user-list"></div>
  `;
  $('#mainView').innerHTML = html;

  // 从服务器加载已提交的选择
  try{
    const choiceResp = await fetch(`/api/choices/${roomId}`);
    const choiceJson = await choiceResp.json();
    if(choiceJson && choiceJson.ok && Array.isArray(choiceJson.data)){
      // 更新本地 userChoices
      userChoices = choiceJson.data;
      saveChoices();
    }
  }catch(err){
    console.error('加载选择数据失败:', err);
  }

  // fill existing choices
  const roomChoices = userChoices.filter(c=>c.room_id===roomId && c.submitted);
  const userMap = {};
  roomChoices.forEach(c=>{
    if(!userMap[c.user_id]) userMap[c.user_id]=[];
    userMap[c.user_id].push(c);
  });

  // 填充当前用户已有的身份选择到界面上
  const currentUser = sampleUsers[0];
  const myChoices = roomChoices.filter(c => c.user_id === currentUser.id);
  myChoices.forEach(choice => {
    const card = $$('.hero-card').find(card => Number(card.dataset.hero) === Number(choice.hero_id));
    if(card){
      const sel = card.querySelector('.identitySel');
      if(sel) sel.value = choice.role;
    }
  });

  // bind copy
  $('#copyLink').addEventListener('click', ()=>{
    const link = `https://example.com/room/${room.id}`;
    navigator.clipboard?.writeText(link).then(()=>alert('已复制链接：'+link), ()=>alert('浏览器不支持自动复制'));
  });

  // bind submit
  $('#submitChoices').addEventListener('click', async ()=>{
    // gather selections
    const cards = $$('.hero-card');
    const currentUser = sampleUsers[0];
    const choicesToSubmit = [];

    cards.forEach(card=>{
      const heroId = Number(card.dataset.hero);
      if(!Number.isFinite(heroId)) return; // skip empty/unknown slots
      const sel = card.querySelector('.identitySel').value;

      choicesToSubmit.push({
        room_id: roomId,
        user_id: currentUser.id,
        hero_id: heroId,
        role: sel
      });

      // save to local userChoices (replace existing)
      const exist = userChoices.find(c=>c.room_id===roomId && c.user_id===currentUser.id && c.hero_id===heroId);
      if(exist){
        exist.role = sel;
        exist.submitted = true;
        exist.updated_at = new Date().toISOString();
      } else {
        userChoices.push({
          room_id:roomId,
          user_id:currentUser.id,
          hero_id:heroId,
          role:sel,
          submitted:true,
          created_at:new Date().toISOString()
        });
      }
    });

    // 保存到服务器
    showLoading('提交中...');
    try{
      for(const choice of choicesToSubmit){
        const resp = await fetch('/api/choices', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(choice)
        });
        const json = await resp.json();
        if(!json || !json.ok){
          console.error('提交选择失败:', choice, json);
        }
      }
      hideLoading();
      alert('提交成功！');
    }catch(err){
      hideLoading();
      showError('提交失败: ' + err.message);
    }

    saveChoices(); // 持久化选择到本地
    renderSubmittedUsers(roomId);
    renderResults(roomId);
  });

  renderSubmittedUsers(roomId);
  renderResults(roomId);

  // 绑定每个卡片下方的搜索框事件（回车替换该卡内容）
  $$('.card-search').forEach((input, i)=>{
    input.addEventListener('keypress', async (e)=>{
      if(e.key==='Enter'){
        const term = input.value.trim();
        if(!term) return;
        const h = await fetchHeroByName(term);
        if(h){
          // 找到当前输入框所属的卡片（向上查找父元素）
          const card = input.closest('.hero-card');
          if(card){
            card.dataset.hero = h.id;
            // h.image_url 已经规范化过了，直接使用
            const img = card.querySelector('img'); if(img) img.src = h.image_url || '/static/img/placeholder.svg';
            const nameInput = card.querySelector('.card-name'); if(nameInput) nameInput.value = h.name;
          }
          // 更新房间数据
          const rIndex = rooms.findIndex(r=>r.id===roomId);
          if(rIndex>=0){
            rooms[rIndex].heroes = rooms[rIndex].heroes || [];
            rooms[rIndex].heroes[i] = h.id;
            saveRooms();
            // 同步到服务器
            await syncRoomHeroesToServer(roomId, rooms[rIndex].heroes);
          }
        } else {
          alert('未找到武将：'+term);
        }
      }
    });
  });

  // 绑定姓名输入框：回车或失焦时触发自动搜索并替换卡位
  $$('.card-name').forEach((input, i)=>{
    const doSearchReplace = async (term)=>{
      term = term.trim(); if(!term) return;
      const h = await fetchHeroByName(term);
      if(h){
        // 找到当前输入框所属的卡片（向上查找父元素）
        const card = input.closest('.hero-card');
        if(card){
          card.dataset.hero = h.id;
          // h.image_url 已经规范化过了，直接使用
          const img = card.querySelector('img'); if(img) img.src = h.image_url || '/static/img/placeholder.svg';
          const nameInput = card.querySelector('.card-name'); if(nameInput) nameInput.value = h.name;
        }
        // 更新房间数据
        const rIndex = rooms.findIndex(r=>r.id===roomId);
        if(rIndex>=0){
          rooms[rIndex].heroes = rooms[rIndex].heroes || [];
          rooms[rIndex].heroes[i] = h.id;
          saveRooms();
          // 同步到服务器
          await syncRoomHeroesToServer(roomId, rooms[rIndex].heroes);
        }
      }
    };
    input.addEventListener('keypress',(e)=>{ if(e.key==='Enter'){ e.preventDefault(); doSearchReplace(input.value); } });
    input.addEventListener('blur', ()=>{ doSearchReplace(input.value); });
  });
}

// 同步房间武将列表到服务器
async function syncRoomHeroesToServer(roomId, heroes){
  try{
    const resp = await fetch(`/api/rooms/${roomId}/heroes`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ heroes })
    });
    const json = await resp.json();
    if(!json || !json.ok){
      console.error('同步武将列表失败:', json);
    }
  }catch(err){
    console.error('同步武将列表失败:', err);
  }
}

function renderSubmittedUsers(roomId){
  const area = $('#submittedUsers');
  area.innerHTML = '';
  const submitted = userChoices.filter(c=>c.room_id===roomId && c.submitted).map(c=>c.user_id).filter((v,i,arr)=>arr.indexOf(v)===i);
  submitted.forEach(uid=>{
  const u = sampleUsers.find(s=>s.id===uid) || {nickname:uid,avatar_url:normalizeImageUrl('img/avatar1.svg')};
    const div = document.createElement('div');
    div.className='user-item';
  div.innerHTML = `<img src="${normalizeImageUrl(u.avatar_url)}" title="查看${u.nickname}的选择" onerror="this.onerror=null;this.src='/static/img/placeholder.svg'"/><div class="small">${u.nickname}</div>`;
    div.addEventListener('click', ()=>showUserChoices(roomId, uid));
    area.appendChild(div);
  });
}

async function showUserChoices(roomId, userId){
  // 如果该用户的选择面板已经存在，则滚动到该面板并避免重复插入
  const panelId = `user-choices-${roomId}-${userId}`;
  const existing = document.getElementById(panelId);
  if(existing){
    existing.scrollIntoView({behavior: 'smooth', block: 'center'});
    // 轻微高亮以提示用户（短暂）
    existing.classList.add('highlight');
    setTimeout(()=>existing.classList.remove('highlight'), 800);
    return;
  }

  const choices = userChoices.filter(c=>c.room_id===roomId && c.user_id===userId && c.submitted);

  // 预加载所有缺失的武将信息
  for(const choice of choices){
    const existInLocal = sampleHeroes.find(h => Number(h.id) === Number(choice.hero_id));
    if(!existInLocal){
      try{
        const resp = await fetch(`/api/heroes?id=${choice.hero_id}`);
        const json = await resp.json();
          if(json && json.ok && json.data && json.data.length > 0){
          await ensureHeroInSample(json.data[0]);
        }
      }catch(err){
        console.error('加载武将信息失败:', choice.hero_id, err);
      }
    }
  }

  // 构建面板头部（包含折叠与关闭按钮）
  const userNick = (sampleUsers.find(u=>u.id===userId)||{nickname:userId}).nickname;
  const rowsHtml = choices.map(c=>{
    const hero = sampleHeroes.find(h=>Number(h.id)===Number(c.hero_id)) || {name:'未知'};
    return `<div class="result-row"><div>${hero.name}</div><div>${c.role}</div></div>`;
  }).join('');

  const html = `
    <div id="${panelId}" class="user-choices-panel">
      <div class="panel-header">
        <h4>${userNick} 的选择</h4>
        <div class="panel-controls">
          <button class="panel-toggle" title="折叠/展开">折叠</button>
          <button class="panel-close" title="关闭">关闭</button>
        </div>
      </div>
      <div class="panel-body">${rowsHtml}</div>
    </div>
  `;
  $('#mainView').insertAdjacentHTML('beforeend', html);
  const panel = document.getElementById(panelId);
  // 绑定折叠按钮
  panel.querySelector('.panel-toggle').addEventListener('click', ()=>{
    panel.classList.toggle('user-choices-collapsed');
    const isCollapsed = panel.classList.contains('user-choices-collapsed');
    panel.querySelector('.panel-toggle').textContent = isCollapsed? '展开' : '折叠';
  });
  // 绑定关闭按钮
  panel.querySelector('.panel-close').addEventListener('click', ()=>{
    panel.remove();
  });
  // 滚动并短暂高亮
  panel.scrollIntoView({behavior: 'smooth', block: 'center'});
  panel.classList.add('highlight');
  setTimeout(()=>panel.classList.remove('highlight'), 800);
}

async function renderResults(roomId){
  const results = {};
  const submitted = userChoices.filter(c=>c.room_id===roomId && c.submitted);
  const area = $('#resultsArea');
  if(submitted.length<2){ area.innerHTML = `<div class="small">尚未达到显示条件（至少2人提交）</div>`; return; }

  // 收集所有需要的武将 ID
  const heroIds = Array.from(new Set(submitted.map(s=>s.hero_id)));

  // 预加载所有缺失的武将信息
  for(const hid of heroIds){
    const existInLocal = sampleHeroes.find(h => Number(h.id) === Number(hid));
    if(!existInLocal){
      try{
        const resp = await fetch(`/api/heroes?id=${hid}`);
        const json = await resp.json();
        if(json && json.ok && json.data && json.data.length > 0){
          await ensureHeroInSample(json.data[0]);
        }
      }catch(err){
        console.error('加载武将信息失败:', hid, err);
      }
    }
  }

  // 计算每个武将的选择分布
  const totalSubmitters = Array.from(new Set(submitted.map(s=>s.user_id))).length;
  const rows = heroIds.map(hid=>{
    const counts = {主公:0,忠臣:0,反贼:0,内奸:0,未知:0};
    submitted.filter(s=>s.hero_id===hid).forEach(s=>counts[s.role] = (counts[s.role]||0)+1);
    const hero = sampleHeroes.find(h=>Number(h.id)===Number(hid))||{name:'未知'};
    const percents = Object.keys(counts).map(k=>({k,v: Math.round((counts[k]/totalSubmitters)*100)}));
    return {hero,counts,percents};
  });

  area.innerHTML = rows.map(r=>{
    const bars = r.percents.map(p=>`<div class="small">${p.k}: ${p.v}%</div>`).join('');
    return `<div class="result-row"><div>${r.hero.name}</div><div class="small">${bars}</div></div>`;
  }).join('');
}

// auto init
window.addEventListener('DOMContentLoaded', init);
